How to generate and publish Angular 5 build files using NodeJS in Asp.net Application
Posted by A2H in AngularJS5, Asp.Net, NodeJS on August 12, 2018
Introduction
In this article we will discuss on the procedures to generate Angular 5 build files from NodeJS. We will also look at Publishing the same files to Deployment folder.
PreRequisites
- Make sure NodeJS is installed in your machine
- Install Angular cli using command “npm i -g @angular/cli@latest”
Description
To generate Angular build files in Asp.Net project, we need to create custom build commands and update the .csproj file. I have copied the commands available on .Net core project to generate angular build files.
After adding the below commands, Asp.Net application will generate angular build files in a folder namely “Dist” in root folder of our project.
To add the commands in cs proj file,
- Right click on project file and select Unload Project option
- Right click again on project file and select Edit option
- Add a Target Node and paste the commands inside it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Target Name="AfterBuild"> | |
<!– Ensure Node.js is installed –> | |
<Exec Command="node –version" ContinueOnError="true"> | |
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" /> | |
</Exec> | |
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." /> | |
<Exec Command="ng build " WorkingDirectory="$(ProjectDir)" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> | |
<Exec Command="ng build" WorkingDirectory="$(ProjectDir)" Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " /> | |
<ItemGroup> | |
<_CustomFiles Include="dist\**\*" /> | |
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)"> | |
<DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension) | |
</DestinationRelativePath> | |
</FilesForPackagingFromProject> | |
</ItemGroup> | |
</Target> |
In above codes first section is to check if node is available on your machine and displays an error message if node is not installed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Exec Command="node –version" ContinueOnError="true"> | |
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" /> | |
</Exec> | |
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." /> |
Next two commands are important as those are the ones which creates angular build files. Notice the “ng build”, this is an Angular CLI command which compiles the application into an output directory. We set two commands one for Release and another one for Debug configuration.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Exec Command="ng build " WorkingDirectory="$(ProjectDir)" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> | |
<Exec Command="ng build" WorkingDirectory="$(ProjectDir)" Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " /> |
Additionally, like ng build, we can also use production build command “ng build –prod”.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ItemGroup> | |
<_CustomFiles Include="dist\**\*" /> | |
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)"> | |
<DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension) | |
</DestinationRelativePath> | |
</FilesForPackagingFromProject> | |
</ItemGroup> |
The Include attribute in _CustomFiles node specifies the folder to find the files for deployment is “dist” All files and folders inside dist folder will be deployed during publish process.
Using Publish to deploy the code in Visual Studio
To deploy the files using Publish option we need to make some additional changes. We need to inform the MsBuild to grab the files from dist folder for deployment. Below commands will perform the same.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<PropertyGroup> | |
<ExcludeFoldersFromDeployment> | |
bin;src | |
</ExcludeFoldersFromDeployment> | |
<CopyAllFilesToSingleFolderForPackageDependsOn> | |
AfterBuild; | |
</CopyAllFilesToSingleFolderForPackageDependsOn> | |
<CopyAllFilesToSingleFolderForMsdeployDependsOn> | |
AfterBuild; | |
</CopyAllFilesToSingleFolderForMsdeployDependsOn> | |
</PropertyGroup> |
Since we are using Asp.Net application project, after build, couple of folders like bin, src will be created. We don’t need these folders for an Angular Project deployment. Hence, we will use below commands to exclude those folders from deployment package.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ExcludeFoldersFromDeployment> | |
bin;src | |
</ExcludeFoldersFromDeployment> |
Next line of code, will cause the “AfterBuild” target to be executed,, when files will be copied for deployment.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<CopyAllFilesToSingleFolderForPackageDependsOn> | |
AfterBuild; | |
</CopyAllFilesToSingleFolderForPackageDependsOn> | |
<CopyAllFilesToSingleFolderForMsdeployDependsOn> | |
AfterBuild; | |
</CopyAllFilesToSingleFolderForMsdeployDependsOn> |
Complete Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Target Name="AfterBuild"> | |
<!– Ensure Node.js is installed –> | |
<Exec Command="node –version" ContinueOnError="true"> | |
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" /> | |
</Exec> | |
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." /> | |
<Exec Command="ng build " WorkingDirectory="$(ProjectDir)" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> | |
<Exec Command="ng build" WorkingDirectory="$(ProjectDir)" Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " /> | |
<ItemGroup> | |
<_CustomFiles Include="dist\**\*" /> | |
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)"> | |
<DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension) | |
</DestinationRelativePath> | |
</FilesForPackagingFromProject> | |
</ItemGroup> | |
</Target> | |
<PropertyGroup> | |
<ExcludeFoldersFromDeployment> | |
bin;src | |
</ExcludeFoldersFromDeployment> | |
<CopyAllFilesToSingleFolderForPackageDependsOn> | |
AfterBuild; | |
</CopyAllFilesToSingleFolderForPackageDependsOn> | |
<CopyAllFilesToSingleFolderForMsdeployDependsOn> | |
AfterBuild; | |
</CopyAllFilesToSingleFolderForMsdeployDependsOn> | |
</PropertyGroup> |
References Used
Getting started with MongoDB in Asp.Net Core
Introduction
In this article we will discuss on the procedures to build a simple application in Asp.Net Core which communicates with MongoDB database.
Description
This application will do the CRUD operation on a Mongo database and then displays the details in a table.
ThirdPartyTool Used
Robo 3T – is a third party tool which provides a lightweight MongoDB management tool
Implementation
Setting up MongoDB:
If you have not installed the mongodb exe then download and install the same from MongoDB Download Center
After installation of the database, in order to access the mongodb we have to start the MongoDB Process.
To start MongoDB, run mongod.exe in command prompt. Make sure you are running the command prompt from installation folder of Mongodb. By default installation path is set as C:\Program Files\MongoDB\Server\3.6\bin\
Additionally we need a data directory to store all data in MongoDB. User can set the path for data files using the –dbpath option to mongod.exe
You can begin using the Robo 3T after starting mongodb process.
For this demo I have created a Collections namely Customer with 3 columns
Since the database is ready now we will start building the application. Follow along the article to create sample application
Below is a sample demonstration of the application we are going to make
Create a new Project in Visual Studio
And Select the Template for Asp.Net Core MVC Web Application
To interact with MongoDB from c# code, we need to install .NET MongoDB Driver which provides asynchronous interaction with MongoDB. I utilized the below nugget commands to add driver into my project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Install-Package Microsoft.EntityFrameworkCore.Tools -Version 2.0.1 | |
Install-Package MongoDB.Driver -Version 2.5.0 |
Model Class
Lets make an entity class called “Customer” which fits the schema of the Customer table in the database
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Customer | |
{ | |
[BsonId] | |
public ObjectId Id { get; set; } | |
[BsonElement] | |
public int CustomerId { get; set; } | |
[BsonElement] | |
public string CustomerName { get; set; } | |
[BsonElement] | |
public string Address { get; set; } | |
} | |
The class contains Id property of the type ObjectId. This property is used to match an item in MongoDB collections. We as well have another attribute, namely BsonElement which is applied to represent an “element” in the MongoDB collection.
Controller Methods
In Controller we will add code for reading, editing, creating and deleting records from MongoDB. I have moved the code to retrieve the mongodb database details to a common method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class HomeController : Controller | |
{ | |
private IMongoDatabase mongoDatabase; | |
//Generic method to get the mongodb database details | |
public IMongoDatabase GetMongoDatabase() | |
{ | |
var mongoClient = new MongoClient("mongodb://localhost:27017"); | |
return mongoClient.GetDatabase("CustomerDB"); | |
} | |
[HttpGet] | |
public IActionResult Index() | |
{ | |
//Get the database connection | |
mongoDatabase = GetMongoDatabase(); | |
//fetch the details from CustomerDB and pass into view | |
var result = mongoDatabase.GetCollection<Customer>("Customers").Find(FilterDefinition<Customer>.Empty).ToList(); | |
return View(result); | |
} | |
[HttpGet] | |
public IActionResult Create() | |
{ | |
return View(); | |
} | |
[HttpPost] | |
public IActionResult Create(Customer customer) | |
{ | |
try | |
{ | |
//Get the database connection | |
mongoDatabase = GetMongoDatabase(); | |
mongoDatabase.GetCollection<Customer>("Customers").InsertOne(customer); | |
} | |
catch (Exception ex) | |
{ | |
throw; | |
} | |
return RedirectToAction("Index"); | |
} | |
[HttpGet] | |
public IActionResult Details(int? id) | |
{ | |
if (id == null) | |
{ | |
return NotFound(); | |
} | |
//Get the database connection | |
mongoDatabase = GetMongoDatabase(); | |
//fetch the details from CustomerDB and pass into view | |
Customer customer = mongoDatabase.GetCollection<Customer>("Customers").Find<Customer>(k => k.CustomerId == id).FirstOrDefault(); | |
if (customer == null) | |
{ | |
return NotFound(); | |
} | |
return View(customer); | |
} | |
[HttpGet] | |
public IActionResult Delete(int? id) | |
{ | |
if (id == null) | |
{ | |
return NotFound(); | |
} | |
//Get the database connection | |
mongoDatabase = GetMongoDatabase(); | |
//fetch the details from CustomerDB and pass into view | |
Customer customer = mongoDatabase.GetCollection<Customer>("Customers").Find<Customer>(k => k.CustomerId == id).FirstOrDefault(); | |
if (customer == null) | |
{ | |
return NotFound(); | |
} | |
return View(customer); | |
} | |
[HttpPost] | |
public IActionResult Delete(Customer customer) | |
{ | |
try | |
{ | |
//Get the database connection | |
mongoDatabase = GetMongoDatabase(); | |
//Delete the customer record | |
var result = mongoDatabase.GetCollection<Customer>("Customers").DeleteOne<Customer>(k => k.CustomerId == customer.CustomerId); | |
if (result.IsAcknowledged == false) | |
{ | |
return BadRequest("Unable to Delete Customer " + customer.CustomerId); | |
} | |
} | |
catch (Exception ex) | |
{ | |
throw; | |
} | |
return RedirectToAction("Index"); | |
} | |
[HttpGet] | |
public IActionResult Edit(int? id) | |
{ | |
if (id == null) | |
{ | |
return NotFound(); | |
} | |
//Get the database connection | |
mongoDatabase = GetMongoDatabase(); | |
//fetch the details from CustomerDB based on id and pass into view | |
var customer = mongoDatabase.GetCollection<Customer>("Customers").Find<Customer>(k => k.CustomerId == id).FirstOrDefault(); | |
if (customer == null) | |
{ | |
return NotFound(); | |
} | |
return View(customer); | |
} | |
[HttpPost] | |
public IActionResult Edit(Customer customer) | |
{ | |
try | |
{ | |
//Get the database connection | |
mongoDatabase = GetMongoDatabase(); | |
//Build the where condition | |
var filter = Builders<Customer>.Filter.Eq("CustomerId", customer.CustomerId); | |
//Build the update statement | |
var updatestatement = Builders<Customer>.Update.Set("CustomerId", customer.CustomerId); | |
updatestatement = updatestatement.Set("CustomerName", customer.CustomerName); | |
updatestatement = updatestatement.Set("Address", customer.Address); | |
//fetch the details from CustomerDB based on id and pass into view | |
var result = mongoDatabase.GetCollection<Customer>("Customers").UpdateOne(filter, updatestatement); | |
if (result.IsAcknowledged == false) | |
{ | |
return BadRequest("Unable to update Customer " + customer.CustomerName); | |
} | |
} | |
catch (Exception ex) | |
{ | |
throw; | |
} | |
return RedirectToAction("Index"); | |
} | |
public IActionResult About() | |
{ | |
ViewData["Message"] = "Your application description page."; | |
return View(); | |
} | |
public IActionResult Contact() | |
{ | |
ViewData["Message"] = "Your contact page."; | |
return View(); | |
} | |
public IActionResult Error() | |
{ | |
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); | |
} | |
} |
Views Code
Since this was a more of a MongoDB demo I have used the scaffolding option available with MVC to generate View. You can modify this as per your needs.
Index View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@model IEnumerable<AspNetCoreMVCMongoDBDemo.Models.Customer> | |
@{ | |
ViewData["Title"] = "Index"; | |
} | |
<h2>Index</h2> | |
<p> | |
<a asp-action="Create">Create New</a> | |
</p> | |
<table class="table table-bordered" style="width:600px"> | |
<thead> | |
<tr> | |
<th> | |
@Html.DisplayNameFor(model => model.CustomerId) | |
</th> | |
<th> | |
@Html.DisplayNameFor(model => model.CustomerName) | |
</th> | |
<th> | |
@Html.DisplayNameFor(model => model.Address) | |
</th> | |
<th>Actions</th> | |
</tr> | |
</thead> | |
<tbody> | |
@foreach (var item in Model) | |
{ | |
<tr> | |
<td> | |
@Html.DisplayFor(modelItem => item.CustomerId) | |
</td> | |
<td> | |
@Html.DisplayFor(modelItem => item.CustomerName) | |
</td> | |
<td> | |
@Html.DisplayFor(modelItem => item.Address) | |
</td> | |
<td> | |
@Html.ActionLink("Edit", "Edit", new { id = item.CustomerId }) | | |
@Html.ActionLink("Details", "Details", new { id = item.CustomerId }) | | |
@Html.ActionLink("Delete", "Delete", new { id = item.CustomerId }) | |
</td> | |
</tr> | |
} | |
</tbody> | |
</table> |
Create View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@model AspNetCoreMVCMongoDBDemo.Models.Customer | |
@{ | |
ViewData["Title"] = "Create"; | |
} | |
<h2>Create Customer Details</h2> | |
<hr /> | |
<div class="row"> | |
<div class="col-md-4"> | |
<form asp-action="Create"> | |
<div asp-validation-summary="ModelOnly" class="text-danger"></div> | |
<div class="form-group"> | |
<label asp-for="CustomerId" class="control-label"></label> | |
<input asp-for="CustomerId" class="form-control" /> | |
<span asp-validation-for="CustomerId" class="text-danger"></span> | |
</div> | |
<div class="form-group"> | |
<label asp-for="CustomerName" class="control-label"></label> | |
<input asp-for="CustomerName" class="form-control" /> | |
<span asp-validation-for="CustomerName" class="text-danger"></span> | |
</div> | |
<div class="form-group"> | |
<label asp-for="Address" class="control-label"></label> | |
<input asp-for="Address" class="form-control" /> | |
<span asp-validation-for="Address" class="text-danger"></span> | |
</div> | |
<div class="form-group"> | |
<input type="submit" value="Create" class="btn btn-default" /> | |
</div> | |
</form> | |
</div> | |
</div> | |
<div> | |
<a asp-action="Index">Back to List</a> | |
</div> | |
@section Scripts { | |
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");} | |
} |
Delete View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@model AspNetCoreMVCMongoDBDemo.Models.Customer | |
@{ | |
Layout = "_Layout"; | |
} | |
<h4>Delete Customer</h4> | |
<div class="row"> | |
<div class="col-md-4"> | |
<form asp-action="Delete"> | |
<label class="control-label">Are you sure to delete </label> <input asp-for="CustomerId" class="form-control" readonly /> | |
<div class="form-group"> | |
<input type="submit" value="Delete" class="btn btn-default" /> | |
</div> | |
</form> | |
</div> | |
</div> | |
<div> | |
<a asp-action="Index">Back to List</a> | |
</div> |
Details View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@model AspNetCoreMVCMongoDBDemo.Models.Customer | |
@{ | |
ViewData["Title"] = "Details"; | |
} | |
<div> | |
<h4>Customer Details</h4> | |
<hr /> | |
<dl class="dl-horizontal"> | |
<dt> | |
@Html.DisplayNameFor(model => model.CustomerId) | |
</dt> | |
<dd> | |
@Html.DisplayFor(model => model.CustomerId) | |
</dd> | |
<dt> | |
@Html.DisplayNameFor(model => model.CustomerName) | |
</dt> | |
<dd> | |
@Html.DisplayFor(model => model.CustomerName) | |
</dd> | |
<dt> | |
@Html.DisplayNameFor(model => model.Address) | |
</dt> | |
<dd> | |
@Html.DisplayFor(model => model.Address) | |
</dd> | |
</dl> | |
</div> | |
<div> | |
<a asp-action="Index">Back to List</a> | |
</div> |
Edit View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@model AspNetCoreMVCMongoDBDemo.Models.Customer | |
@{ | |
Layout = "_Layout"; | |
} | |
@{ | |
ViewData["Title"] = "Details"; | |
} | |
<h2>Edit Customer Details</h2> | |
<hr /> | |
<div class="row"> | |
<div class="col-md-4"> | |
<form asp-action="Edit"> | |
<div asp-validation-summary="ModelOnly" class="text-danger"></div> | |
<div class="form-group"> | |
<label asp-for="CustomerId" class="control-label"></label> | |
<input asp-for="CustomerId" class="form-control" /> | |
</div> | |
<div class="form-group"> | |
<label asp-for="CustomerName" class="control-label"></label> | |
<input asp-for="CustomerName" class="form-control" /> | |
<span asp-validation-for="CustomerName" class="text-danger"></span> | |
</div> | |
<div class="form-group"> | |
<label asp-for="Address" class="control-label"></label> | |
<input asp-for="Address" class="form-control" /> | |
<span asp-validation-for="Address" class="text-danger"></span> | |
</div> | |
<div class="form-group"> | |
<input type="submit" value="Save" class="btn btn-default" /> | |
</div> | |
</form> | |
</div> | |
</div> | |
<div> | |
<a asp-action="Index">Back to List</a> | |
</div> |
Conclusion
In this article we have looked into procedures to create a simple application in MVC Core using MongoDB as database.
You can download the source code for Asp.NetCoreMVCMongoDBDemo from GitHub.
Host WCF Service in Azure App Service
Posted by A2H in Microsoft Azure, WCF on November 13, 2017
Introduction
In this article we will discuss on the procedures to host a WCF Service on WebApps in Azure App Service. Azure App Serivce consists of four sub types and they are
- Web Apps – Provides hosting service for Web Applications
- Mobile Apps – Provides a mobile-application development platform that’s highly scalable.
- Logic Apps – Provides a visual designer to automate the business process in a series of workflow
- API Apps – Provides design and hosting services for Rest API
Description
Usually we use Cloud Services on Azure to host WCF services. While Cloud Services hosting works as expected, the requirement we got was to find an option to host wcf service using one of the features in Azure AppService itself.
We can use WebApps feature to host the WCF in Azure AppService. Follow along this article to find out the procedures.
Step 1: Right Click on WCF Project in Visual Studio and Select the Publish Option
Step 2: Publish dialog box will display. In that Select the Microsoft Azure AppService option. If you are deploying WCF Service for the first time then select “Create New” and click on Publish Button
Step 3: Now we will see the App Service configuration dialog window. In the dialog window, we have to create the configuration details for WebApp in Azure
- App Name – Name of the hosted wcf service application in azure
- Subscription – Your active subscription for Azure. This field will be auto populated when you login to azure
- Resource Group – Enables you to work with the resources in your solution as a
- App Service Plan – Option to select the deployment location and the App Service Plan for deployment
Step 4: Before publishing to Azure, Make sure the application type is “Web App”
Step 5: Click on Create button to start deployment to Azure. You can also find the status of deployment in Output Window of Visual Studio
Step 6: After successful deployment, the published WCF Service will be displayed on the App Service section on Azure portal.Step 7: Click on Published WCF Service to find more details and URL of service.
Accessing the WCF Service
Create a console app as client application for WCF Service. Right click on console app and use the Add -> Service Reference option to access wcf service on client application
Once we add the WCF Service reference, we can call the WCF method like below
Simple CRUD Application in Asp.Net Core Razor Pages
Posted by A2H in Asp.Net Core, Razor Pages on October 22, 2017
Introduction:
This article presents how to produce a simple application using Razor Pages in Asp.Net Core. This application will do the CRUD operation on a SQL Server database and then displays the details in a table.
You require to have Visual Studio 2017 Version 15.3 and .NET Core 2.0 installed in order to work with Razor Page Applications. You can get more details from here
Implementation
Create a new Project in Visual Studio
And Select the Web Application Template for Razor Pages
Project Structure
If you take a look at the project structure you will notice the main difference in Razor Pages is that there is No Controller and Views folder. All files in Razor Pages are inside the “pages” folder. You can also create subfolders within the pages folder to keep the files organized.
Another important point to note is the @page directive on the RazorPages. @page directive will cause the file to handle the requests directly, without utilizing a controller.
Sample Application:
Now let’s start building a simpler application which performs CRUD operations on Employee database using Razor Pages. Below is a sample demonstration of the application we are going to make.
Model and Database
To load the information from database, we are using EntityFrameworkCore and its associated methods. Make sure you install the EF Core nugget packages from here
In this example I have used the DatabaseFirstApporach. DatabaseFirstApporach lets the EnityData Model to generate classes, dbcontext etc from the database automatically. All other functionalities like database and model sync exists as is.
Let’s create an entity class called “Employee” which matches the schema of the Employee Table in the database
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Employee | |
{ | |
[Key] | |
public int EmployeeID { get; set; } | |
[Required] | |
public string EmployeeName { get; set; } | |
[Required] | |
public string EmployeeAddress { get; set; } | |
} |
Next we will add a DbContext class , which will act as a session between entity class and database.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class EmployeeDbContext : DbContext | |
{ | |
public EmployeeDbContext(DbContextOptions<EmployeeDbContext> options) : base(options) | |
{ | |
} | |
public DbSet<Employee> Employee { get; set; } | |
} |
Next we will provide the connection string for database in appsettings.json file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"Logging": { | |
"IncludeScopes": false, | |
"LogLevel": { | |
"Default": "Warning" | |
} | |
}, | |
"ConnectionStrings": { | |
"EmployeeDbContext": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=C:\\LEARNING\\BLOG\\NETCORERAZORPAGEAPP\\NETCORERAZORPAGEAPP\\APPDATA\\EMPLOYEEDB.MDF;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" | |
} | |
} |
Finally we will register dbContext using dependency injection. Modify the startup.cs file and add the below code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddDbContext<EmployeeDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("EmployeeDbContext"))); | |
services.AddMvc(); | |
} |
Adding Views for Create, Edit, Update, Delete (CRUD)
Create View (CreatePage.cshtml)
On Create page we used 3 directives.
@page: Razor Pages mandates that “@page” directive should be the first directive on page.
@inject: Another directive you can find on page is @inject. @inject directive is used for dependency injection in to views. Using @inject we inject the dbContext to View, which will be used to for all db related operations.
@functions: In Razor page, we can add the function-level content code(C#) to view. We can also have the content in code behind CreatePage.cshtml.cs page.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@page | |
@*Adding the reference of model class*@ | |
@using NetCoreRazorPageApp.Model | |
@using Microsoft.EntityFrameworkCore; | |
@{ | |
ViewData["Title"] = "Home page"; | |
} | |
@inject NetCoreRazorPageApp.Model.EmployeeDbContext dbcontext | |
@functions { | |
[BindProperty] | |
public NetCoreRazorPageApp.Model.Employee Employee { get; set; } | |
//Method to create employee record in database | |
public async Task<IActionResult> OnPostAsync() | |
{ | |
if (!ModelState.IsValid) | |
{ | |
return Page(); | |
} | |
dbcontext.Employee.Add(Employee); | |
await dbcontext.SaveChangesAsync(); | |
return RedirectToPage("/Index"); | |
} | |
} | |
<form method="post"> | |
<div> | |
<div> | |
<label for="txtEmpName">Employee Name :</label><input id="txtEmpName" type="text" asp-for="Employee.EmployeeName" class="form-control" style="width:250px" /> | |
</div> | |
<div> | |
<label for="txtEmpName">Employee Address :</label><input id="txtEmpAddress" type="text" style="width:250px" asp-for="Employee.EmployeeAddress" class="form-control" /> | |
</div> | |
<div style="height:50px;"></div> | |
<div> | |
<input id="Button1" type="submit" value="Save" class="btn btn-primary" /> | |
</div> | |
</div> | |
</form> |
Edit View
Next we will see the EditPage. Most of the coding are similar to create page which we already seen earlier. However in this page, we need to pass the selected row id as route parameter
We used asp-route-{value} attribute from anchor tag helper to generate the Edit Link. At runtime the {value} field (in our example ‘id’) will be mapped to the route parameter value which will be used by Edit Page to retrieve the selected row value.
<a asp-page="/EditPage" asp-route-id="@item.EmployeeID">Edit</a>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@page "{id:int}" | |
@model EditPageModel | |
@{ | |
} | |
<h2>Edit</h2> | |
<form method="post"> | |
<table class="table table-bordered" style="width:500px"> | |
<tbody> | |
<tr> | |
<td> | |
<input asp-for="Employee.EmployeeID" type="hidden" /> | |
<label for="txtEmpName">Employee Name :</label> | |
</td> | |
<td> | |
<input id="txtEmpName" type="text" asp-for="Employee.EmployeeName" class="form-control" style="width:250px" /> | |
</td> | |
</tr> | |
<tr> | |
<td><label for="txtEmpName">Employee Address :</label></td> | |
<td><input id="txtEmpAddress" type="text" style="width:250px" asp-for="Employee.EmployeeAddress" class="form-control" /></td> | |
</tr> | |
<tr> | |
<td colspan="2"><input id="Button1" type="submit" value="Save" class="btn btn-primary" /> | <a asp-page="/Index" class="btn btn-primary">Back</a></td> | |
</tr> | |
</tbody> | |
</table> | |
</form> |
EditPage.cshtml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.AspNetCore.Mvc.RazorPages; | |
using Microsoft.EntityFrameworkCore; | |
namespace NetCoreRazorPageApp.Pages | |
{ | |
public class EditPageModel : PageModel | |
{ | |
//Creating dbContext object | |
public readonly NetCoreRazorPageApp.Model.EmployeeDbContext _dbContext; | |
public EditPageModel(NetCoreRazorPageApp.Model.EmployeeDbContext dbContext) | |
{ | |
_dbContext = dbContext; | |
} | |
[BindProperty] | |
public NetCoreRazorPageApp.Model.Employee Employee { get; set; } | |
//Method to retreive the selected record details | |
public async Task<IActionResult> OnGetAsync(int? id) | |
{ | |
if (id == null) | |
{ | |
return NotFound(); | |
} | |
//Get the value from database based on ID | |
Employee = await _dbContext.Employee.FirstOrDefaultAsync(i => i.EmployeeID == id); | |
if (Employee == null) | |
{ | |
return NotFound(); | |
} | |
return Page(); | |
} | |
//Method to save the data back to database | |
public async Task<IActionResult> OnPostAsync() | |
{ | |
try | |
{ | |
//Updating modified Employee details to database | |
_dbContext.Attach(Employee).State = EntityState.Modified; | |
await _dbContext.SaveChangesAsync(); | |
} | |
catch (Exception ex) | |
{ | |
throw ex; | |
} | |
//Redirecting back to Index page after successfull save | |
return RedirectToPage("./Index"); | |
} | |
} | |
} |
All other pages have the similar code structure. The difference is only the operation performed on each pages. All codes have comments added which are select explanatory
Index View(Home Page)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@page | |
@using NetCoreRazorPageApp.Model | |
@using Microsoft.EntityFrameworkCore; | |
@inject EmployeeDbContext dbcontext | |
@functions { | |
public IEnumerable<NetCoreRazorPageApp.Model.Employee> Employees { get; set; } | |
public async Task OnGetAsync() | |
{ | |
//Retreive 10 records from database | |
Employees = await dbcontext.Employee.Take(10).ToListAsync(); | |
} | |
} | |
<form method="post"> | |
<br /><br /> | |
<a asp-page="/CreatePage" class="btn btn-primary">Create</a> | |
<br /><br /> | |
Details | |
<table class="table table-sm table-bordered table-striped"> | |
<thead class="green-gray lighten-4"> | |
<tr> | |
<th>Employee ID</th> | |
<th>Employee Name</th> | |
<th>Employee Address</th> | |
<th>Actions</th> | |
</tr> | |
</thead> | |
<tbody> | |
@foreach (var item in Model.Employees) | |
{ | |
<tr> | |
<td>@item.EmployeeID</td> | |
<td>@item.EmployeeName</td> | |
<td>@item.EmployeeAddress</td> | |
<td><a asp-page="/EditPage" asp-route-id="@item.EmployeeID">Edit</a> | <a asp-page="/DeletePage" asp-route-id="@item.EmployeeID">Delete</a> </td> | |
</tr> | |
} | |
</tbody> | |
</table> | |
</form> |
Delete View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@page "{id:int}" | |
@model NetCoreRazorPageApp.Pages.Employee.DeletePageModel | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name="viewport" content="width=device-width" /> | |
<title>DeletePage</title> | |
</head> | |
<body> | |
<h4>Delete Employee Record</h4> | |
<h5>Are you sure you want to delete this?</h5> | |
<table class="table table-bordered" style="width:250px"> | |
<tbody> | |
<tr> | |
<td> | |
<label for="txtEmpName">Employee Name :</label> | |
</td> | |
<td> | |
@Html.DisplayFor(model => model.Employee.EmployeeName) | |
</td> | |
</tr> | |
<tr> | |
<td><label for="txtEmpName">Employee Address :</label></td> | |
<td>@Html.DisplayFor(model => model.Employee.EmployeeAddress)</td> | |
</tr> | |
</tbody> | |
</table> | |
<form method="post"> | |
<table> | |
<tbody> | |
<tr> | |
<td> | |
<input asp-for="Employee.EmployeeID" type="hidden" /> | |
</td> | |
<td colspan="2"><input id="Button1" type="submit" value="Delete" class="btn btn-primary" /> | <a asp-page="./Index" class="btn btn-primary">Cancel</a></td> | |
</tr> | |
</tbody> | |
</table> | |
</form> | |
</body> | |
</html> |
DeletePage.cshtml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.AspNetCore.Mvc.RazorPages; | |
using Microsoft.EntityFrameworkCore; | |
namespace NetCoreRazorPageApp.Pages.Employee | |
{ | |
public class DeletePageModel : PageModel | |
{ | |
public readonly NetCoreRazorPageApp.Model.EmployeeDbContext _dbContext; | |
public DeletePageModel(NetCoreRazorPageApp.Model.EmployeeDbContext dbContext) | |
{ | |
_dbContext = dbContext; | |
} | |
[BindProperty] | |
public NetCoreRazorPageApp.Model.Employee Employee { get; set; } | |
//Method to retreive the selected record details | |
public async Task<IActionResult> OnGetAsync(int? id) | |
{ | |
if (id == null) | |
{ | |
return NotFound(); | |
} | |
//Get the value from database based on ID | |
Employee = await _dbContext.Employee.FirstOrDefaultAsync(i => i.EmployeeID == id); | |
if (Employee == null) | |
{ | |
return NotFound(); | |
} | |
return Page(); | |
} | |
//Method to Delete record from database | |
public async Task<IActionResult> OnPostAsync(int? id) | |
{ | |
if (id == null) | |
{ | |
return NotFound(); | |
} | |
//Delete Employee details to database | |
Employee = await _dbContext.Employee.FindAsync(id); | |
if (Employee != null) | |
{ | |
_dbContext.Employee.Remove(Employee); | |
await _dbContext.SaveChangesAsync(); | |
} | |
//Redirecting back to Index page after successfull Delete operation | |
return RedirectToPage("/Index"); | |
} | |
} | |
} |
You can find complete code of this demo from here
[Solution]Dropdownlist not retaining selected item on Postback
Posted by A2H in Trouble Shooting on August 26, 2017
Introduction
In this article we will look into an alternative solution to the problem with dropdownlist where selecteditems are not retained on postback.
Problem Description
When we select an item in dropdownlist and do a postback(button click) then the value selected on dropdownlist will reset to the first item in dropdownlist.
Usually this issue happens when we reload the items in dropdownlist on every postback. To resolve the issue we will load the dropdownlist inside the If(!IsPostBack) block.
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { DropDownList2.Items.Insert(0, new ListItem("One", "")); DropDownList2.Items.Insert(1, new ListItem("Two", "")); DropDownList2.Items.Insert(2, new ListItem("Three", "")); DropDownList2.Items.Insert(3, new ListItem("Four", "")); DropDownList2.Items.Insert(4, new ListItem("Five", "")); DropDownList2.Items.Insert(5, new ListItem("Six", "")); DropDownList2.Items.Insert(6, new ListItem("Seven", "")); DropDownList2.Items.Insert(7, new ListItem("Eight", "")); DropDownList2.Items.Insert(8, new ListItem("Nine", "")); DropDownList2.Items.Insert(9, new ListItem("Ten", "")); DropDownList2.SelectedIndex = 4; } }
However if you see the code preceding, you will notice that the dropdownlist is populated inside if(!IsPostBack) block. Now what is causing the issue?
Solution:
On further analysis I noticed that while populating the dropdownlist, user is passing an empty string to “value” property of dropdownlist. Dropdownlist will render on page at runtime without value being populated. This invalid code for dropdownlist caused the issue.
<select name="DropDownList2" id="DropDownList2"> <option value="">One</option> <option value="">Two</option> <option value="">Three</option> <option value="">Four</option> <option selected="selected" value=""> Five</option> <option value="">Six</option> <option value="">Seven</option> <option value="">Eight</option> <option value="">Nine</option> <option value="">Ten</option> </select>
To resolve the issue we need to provide an entry to “value” property in dropdownlist.
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { DropDownList2.Items.Insert(0, new ListItem("One", "1")); DropDownList2.Items.Insert(1, new ListItem("Two", "2")); DropDownList2.Items.Insert(2, new ListItem("Three", "3")); DropDownList2.Items.Insert(3, new ListItem("Four", "4")); DropDownList2.Items.Insert(4, new ListItem("Five", "5")); DropDownList2.Items.Insert(5, new ListItem("Six", "6")); DropDownList2.Items.Insert(6, new ListItem("Seven", "7")); DropDownList2.Items.Insert(7, new ListItem("Eight", "8")); DropDownList2.Items.Insert(8, new ListItem("Nine", "9")); DropDownList2.Items.Insert(9, new ListItem("Ten", "10")); DropDownList2.SelectedIndex = 4; } }
Demo
Bundling and Minification in AspNetCore
Posted by A2H in Asp.Net Core on August 23, 2017
Introduction:
In this article we will look into an easy option to do bundling and minification in Asp.Net Core. For those who are new to Bundling and Minification let’s try to understand these concepts.
Bundling
Bundling is the process of combining multiple javascript files to a single file. By this way we will reduce the number of requests needed for loading the files. i.e. if we had javascript code in multiple files then system will generate multiple requests to load all files however since we bundled all files there will be only one requests to load file. This will improve the load time.
Minification
Minification is the process of reducing the size of files (css , javascript). Usually size reduction happens by removing unwanted spaces in file.
For ex, below Javascript code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function SampleCode() | |
{ | |
var i = 1; | |
var j = 2; | |
alert(i + j); | |
} |
will change like below after minification.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function SampleCode(){alert(3)} |
Bundling and Minification using Gulp
We have variety of options available for Third party tools like Gulp and Grunt can be used to do bundling and minification process. However the problem with this approach is it involves additional steps which are slightly complex.
Using Bundler and Minification Extension
Mads Kristensen has created an extension namely “Bundler and Minifier”, using this we can easily do both bundling and minification in Asp.netCore. You can download the installer for extension from here.
Once you installed the extension, to do bundling and minification all you do is to Right click on the file and then select Bundler & Minifier option.
If you have a single javascript file then you will see the only Minify File option.
Once you select the option extension will generate the minified file for us. We can also follow the same process to minify css files as well.
Finding Textbox control based on a selected row in Jquery
Posted by A2H in Uncategorized on July 12, 2017
Introduction
In this article I will demonstrate the steps to find the Textbox control from the selected row in repeater using Jquery.
Implementation
We use a Radiobuttonlist to select each rows. Requirement is to disable and enable the textbox based on the selected radiobutton value for particular row. If user selected Yes then enable the textbox and if user selected No then enable textbox. You can use the below Jquery code to find the selected repeater row and then disable and enable textbox control based on selected value.
Jquery Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://code.jquery.com/jquery-3.0.0.js"></script> | |
<script type="text/javascript"> | |
$(document).ready(function () { | |
//Attach change event to radiobuttonlist controls | |
$("input:radio").change(function (obj) { | |
//Get the selected radiobutton value | |
var type = $.trim($(this).val()); | |
//check if value selected is equal to Yes | |
if (type == "Yes") { | |
//find the textbox control based on selected radiobutton control | |
//Use the props to enable and disable the textbox control | |
$(this).closest(".container").find(".txtbox").prop("disabled", false); | |
} | |
else | |
$(this).closest(".container").find(".txtbox").prop("disabled", true); | |
}); | |
}); | |
</script> |
Complete Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head runat="server"> | |
<title></title> | |
<script src="https://code.jquery.com/jquery-3.0.0.js"></script> | |
<script type="text/javascript"> | |
$(document).ready(function () { | |
//Attach change event to radiobuttonlist controls | |
$("input:radio").change(function (obj) { | |
//Get the selected radiobutton value | |
var type = $.trim($(this).val()); | |
//check if value selected is equal to Yes | |
if (type == "Yes") { | |
//find the textbox control based on selected radiobutton control | |
//Use the props to enable and disable the textbox control | |
$(this).closest(".container").find(".txtbox").prop("disabled", false); | |
} | |
else | |
$(this).closest(".container").find(".txtbox").prop("disabled", true); | |
}); | |
}); | |
</script> | |
</head> | |
<body> | |
<form id="form1" runat="server"> | |
<div> | |
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1"> | |
<ItemTemplate> | |
<table> | |
<tr> | |
<td class="container"> | |
<asp:RadioButtonList ID="rblIssues" runat="server" RepeatDirection="Horizontal" TextAlign="Right"> | |
<asp:ListItem Text="Yes" /> | |
<asp:ListItem Text="No" /> | |
</asp:RadioButtonList><br /> | |
<asp:TextBox ID="txtOnwerName" CssClass="txtbox" Enabled="false" runat="server" Text="Sample Value"></asp:TextBox> | |
</td> | |
</tr> | |
</table> | |
</ItemTemplate> | |
</asp:Repeater> | |
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:AdventureWorksConnectionString %>" | |
SelectCommand="SELECT top 10 [AccountKey], [ParentAccountKey], [AccountCodeAlternateKey] FROM [DimAccount]"></asp:SqlDataSource> | |
</div> | |
</form> | |
</body> | |
</html> |
Demo
You can find complete source code here
Insert functionality in UIGrid
Introduction
This is a continuation of my previous articles in which I demonstrated the procedure to
In this article I will demonstrate how to implement Add new record functionality in Angular UIGrid.
Prerequisites:
I have used icons from FontAwesome Library, which is a great source for multiple icons. You can download Fontawesome icons from here.
To display message after every operation we used UIBootstrap.
Implementation:
You would already have the Model configured by following my previous article on loading UIGrid with data. We will directly look into the details of Adding new record in UIGrid.
You can see a sample Demo of entire functionality below.
UIGrid Updates
We will add a new button on page which responds to click event and open a modal pop up window. Users can enter the details and on save button click we will save the data to database.
AddCustomer function:
AddCustomer function will take the scope object as input which contains all values as provided by user and then save the data to database. User will also see an alert stating the status of insert operation.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$scope.AddCustomer = function () { | |
//Assign the updated value to Customer object | |
$scope.Customer.customerID = $scope.txtCustomerNameVal; | |
$scope.Customer.companyName = $scope.txtCompanyNameVal; | |
$scope.Customer.contactName = $scope.txtContactNameVal; | |
$scope.Customer.contactTitle = $scope.txtContactTitleVal; | |
//Call the factory function to insert the customer | |
CustomerService.AddCustomer($scope).then(function (d) { | |
alert(d.data); | |
}, function (d) { | |
alert(d); | |
}); | |
//calling the function to close the modal popup | |
$scope.closeModalWindow(); | |
}; |
Updated Angular code with Insert new Record functionality
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Adding ui grid module as a depedency in app | |
var app = angular.module('app', ['ui.grid', 'ui.bootstrap']); | |
//Controller function to load the data | |
app.controller('MainCtrl', function ($scope, $http, CustomerService, $uibModal) { | |
//function to be called on row edit button click | |
//Passing the selected row object as parameter, we use this row object to identify the edited row | |
$scope.edit = function (row) { | |
//Get the index of selected row from row object | |
var index = $scope.gridOptions.data.indexOf(row); | |
//Use that to set the editrow attrbute value for seleted rows | |
$scope.gridOptions.data[index].editrow = !$scope.gridOptions.data[index].editrow; | |
}; | |
//Method to cancel the edit mode in UIGrid | |
$scope.cancelEdit = function (row) { | |
//Get the index of selected row from row object | |
var index = $scope.gridOptions.data.indexOf(row); | |
//Use that to set the editrow attrbute value to false | |
$scope.gridOptions.data[index].editrow = false; | |
//Display Successfull message after save | |
$scope.alerts.push({ | |
msg: 'Row editing cancelled', | |
type: 'info' | |
}); | |
}; | |
//Class to hold the customer data | |
$scope.Customer = { | |
customerID: '', | |
companyName: '', | |
contactName: '', | |
contactTitle: '' | |
}; | |
$scope.alerts = []; | |
//Function to save the data | |
//Here we pass the row object as parmater, we use this row object to identify the edited row | |
$scope.saveRow = function (row) { | |
//get the index of selected row | |
var index = $scope.gridOptions.data.indexOf(row); | |
//Remove the edit mode when user click on Save button | |
$scope.gridOptions.data[index].editrow = false; | |
//Assign the updated value to Customer object | |
$scope.Customer.customerID = row.CustomerID; | |
$scope.Customer.companyName = row.CompanyName; | |
$scope.Customer.contactName = row.ContactName; | |
$scope.Customer.contactTitle = row.ContactTitle; | |
//Call the function to save the data to database | |
CustomerService.SaveCustomer($scope).then(function (d) { | |
//Display Successfull message after save | |
$scope.alerts.push({ | |
msg: 'Data saved successfully', | |
type: 'success' | |
}); | |
}, function (d) { | |
//Display Error message if any error occurs | |
$scope.alerts.push({ | |
msg: d.data, | |
type: 'danger' | |
}); | |
}); | |
}; | |
$scope.alerts = []; | |
//Function to delete the row | |
//Here we pass the row object as parmater, we use this row object to identify the row to be deleted | |
$scope.deleteRow = function (row) { | |
//Display a confirm message box before deleting records | |
var returnvalue = confirm("Are you sure to delete customer " + row.ContactName); | |
//Delete the row only if user selects ok | |
if (returnvalue == true) { | |
//Get the customer id from selected row | |
$scope.Customer.customerID = row.CustomerID; | |
//Call the factory function to delete the customer | |
CustomerService.DeleteCustomer(row.CustomerID).then(function (d) { | |
//Call function to load the updated data after deleting record | |
$scope.GetCustomer(); | |
//Display Successfull message after Delete | |
$scope.alerts.push({ | |
msg: 'Customer Deleted successfully', | |
type: 'success' | |
}); | |
}, function (d) { | |
//Display Error message if any error occurs | |
$scope.alerts.push({ | |
msg: d.data, | |
type: 'danger' | |
}); | |
}); | |
} | |
}; | |
//function to open the modal window popup | |
$scope.open = function () { | |
$scope.$modalInstance = $uibModal.open({ | |
animation: true, | |
templateUrl: 'ModalWindow.html', | |
scope: $scope, | |
controller: 'MainCtrl', | |
size: 'md' | |
}); | |
}; | |
$scope.closeModalWindow = function () { | |
$scope.$modalInstance.close(); | |
} | |
$scope.alerts = []; | |
$scope.AddCustomer = function () { | |
//Assign the updated value to Customer object | |
$scope.Customer.customerID = $scope.txtCustomerNameVal; | |
$scope.Customer.companyName = $scope.txtCompanyNameVal; | |
$scope.Customer.contactName = $scope.txtContactNameVal; | |
$scope.Customer.contactTitle = $scope.txtContactTitleVal; | |
//Call the factory function to insert the customer | |
CustomerService.AddCustomer($scope).then(function (d) { | |
alert(d.data); | |
}, function (d) { | |
alert(d); | |
}); | |
//calling the function to close the modal popup | |
$scope.closeModalWindow(); | |
}; | |
//Get function to populate the UI-Grid | |
$scope.GetCustomer = function () { | |
$scope.gridOptions = { | |
//Declaring column and its related properties | |
columnDefs: [ | |
{ | |
name: "CustomerID", displayName: "Customer ID", field: "CustomerID", | |
cellTemplate: '<div ng-if="!row.entity.editrow">{{COL_FIELD}}</div><div ng-if="row.entity.editrow"><input type="text" style="height:30px" ng-model="MODEL_COL_FIELD"</div>', width: 80 | |
}, | |
{ | |
name: "CompanyName", displayName: "Company Name", field: "CompanyName", | |
cellTemplate: '<div ng-if="!row.entity.editrow">{{COL_FIELD}}</div><div ng-if="row.entity.editrow"><input type="text" style="height:30px" ng-model="MODEL_COL_FIELD"</div>', width: 200 | |
}, | |
{ | |
name: "ContactName", displayName: "Contact Name", field: "ContactName", | |
cellTemplate: '<div ng-if="!row.entity.editrow">{{COL_FIELD}}</div><div ng-if="row.entity.editrow"><input type="text" style="height:30px" ng-model="MODEL_COL_FIELD"</div>', width: 140 | |
}, | |
{ | |
name: "ContactTitle", displayName: "Contact Title", field: "ContactTitle", | |
cellTemplate: '<div ng-if="!row.entity.editrow">{{COL_FIELD}}</div><div ng-if="row.entity.editrow"><input type="text" style="height:30px" ng-model="MODEL_COL_FIELD"</div>', width: 140 | |
}, | |
{ | |
name: 'Actions', field: 'edit', enableFiltering: false, enableSorting: false, | |
cellTemplate: '<div><button ng-show="!row.entity.editrow" class="btn primary" ng-click="grid.appScope.edit(row.entity)"><i class="fa fa-edit"></i></button>' + //Edit Button | |
'<button ng-show="row.entity.editrow" class="btn primary" ng-click="grid.appScope.saveRow(row.entity)"><i class="fa fa-floppy-o"></i></button>' +//Save Button | |
'<button ng-show="row.entity.editrow" class="btn primary" ng-click="grid.appScope.cancelEdit(row.entity)"><i class="fa fa-times"></i></button>' + //Cancel Button | |
'<button ng-show="!row.entity.editrow" class="btn primary" ng-click="grid.appScope.deleteRow(row.entity)"><i class="fa fa-trash-o"></i></button>' +//Delete Button | |
'</div>', width: 150 | |
} | |
], | |
onRegisterApi: function (gridApi) { | |
$scope.gridApi = gridApi; | |
} | |
}; | |
//Function load the data from database | |
CustomerService.GetCustomer().then(function (d) { | |
$scope.gridOptions.data = d.data; | |
}, function (d) { | |
alert(d.data); | |
}); | |
}; | |
//Call function to load the data | |
$scope.GetCustomer(); | |
}); | |
//Factory methods to call WebAPI controller methods | |
app.factory('CustomerService', function ($http) { | |
var res = {}; | |
res.GetCustomer = function () { | |
return $http({ | |
method: 'GET', | |
dataType: 'jsonp', | |
url: 'api/Customer/GetCustomer' | |
}); | |
} | |
res.SaveCustomer = function ($scope) { | |
return $http({ | |
method: 'POST', | |
data: $scope.Customer, | |
url: 'api/Customer/UpdateCustomer' | |
}); | |
} | |
res.DeleteCustomer = function (customerID) { | |
return $http.delete('api/Customer/DeleteCustomer?customerID=' + customerID); | |
} | |
res.AddCustomer = function ($scope) { | |
return $http({ | |
method: 'PUT', | |
data: $scope.Customer, | |
url: 'api/Customer/AddCustomer' | |
}); | |
} | |
return res; | |
}); |
Modal Pop up HTML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script type="text/ng-template" id="ModalWindow.html"> | |
<div class="modal-header"> | |
<h3 class="modal-title">Add new Record</h3> | |
</div> | |
<div class="modal-body"> | |
<div class="table-responsive"> | |
<table class="col-md-12 table-bordered table-striped table-condensed"> | |
<tbody> | |
<tr> | |
<td>Customer Name</td> | |
<td><input type="text" id="txtCustomerName" ng-model="txtCustomerNameVal" class="form-control" /></td> | |
</tr> | |
<tr> | |
<td>Company Name</td> | |
<td><input type="text" id="txtCompanyName" class="form-control" ng-model="txtCompanyNameVal" /></td> | |
</tr> | |
<tr> | |
<td>Contact Name</td> | |
<td><input type="text" id="txtContactName" class="form-control" ng-model="txtContactNameVal" /></td> | |
</tr> | |
<tr> | |
<td>Contact Title</td> | |
<td><input type="text" id="txtContactTitle" class="form-control" ng-model="txtContactTitleVal" /></td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
</div> | |
<div class="modal-footer"> | |
<button class="btn btn-success" type="button" ng-click="AddCustomer()" id="btnSave">Save</button> | |
<button class="btn btn-warning" type="button" ng-click="closeModalWindow()">Cancel</button> | |
</div> | |
</script> |
WEBAPI AddCustomer Method
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[HttpPut] | |
public IHttpActionResult AddCustomer(Customer customer) | |
{ | |
try | |
{ | |
dbContext.Customers.Add(customer); | |
dbContext.SaveChanges(); | |
return Content(HttpStatusCode.OK, "Customer" + customer.ContactName + " has been created"); | |
} | |
catch (Exception ex) | |
{ | |
return Content(HttpStatusCode.InternalServerError, "Inserting customer failed : " + ex.Message); | |
} | |
} |
You can find complete source code of this demo from github